param(
	[Parameter(Mandatory=$false)]                             
	[string]$inputFile="inputlist.txt",     # the input file to store vdi,domain and fid list
	[Parameter(Mandatory=$false)]                             
	[switch]$inputFileSaved,               # tell if inputfile has been saved, otherwise will popup text to let user enter VDI list.
	[Parameter(Mandatory=$false)]                             
	[switch]$functionInvoked              # tell if script needs to invoke functions
)
$st=get-date
$this_path = Split-Path -Parent ($MyInvocation.MyCommand.Definition) # get the directory of this running script
$parent_path=(get-item $this_path).Parent.FullName
If( !$functionInvoked ){
	. "$parent_path\functions.ps1" # import functions to powershell from functions.ps1
}
If( $inputFile -notlike "*\*"){
    $inputFile="$this_path\$inputFile"
}
$inputlist=Get-Inputlist $inputFile $inputFileSaved
#<------------------------------------------------------HPCA Setting Checking------------------------------------------------------>
$hpca_temp_path="$this_path\temp" # used to store each result csv file from end vdi incase the script breaks in the middle of running unexpectedly so that we can check the file and know which ones we have already checked
del "$hpca_temp_path\*.csv" -Force -ErrorAction Ignore
del "$this_path\*.csv" -Force -ErrorAction Ignore
#<---------------------------initilize script block for parallel threads running--------------------------->
$hpca_action={
	param($line,$cnt,$ActionParams)
	Function Get-EnvOrPackageBy(){
		param(
			[Parameter(Mandatory=$True)]
			[ValidateSet("env", "pack")]
			[string]$kind,
			[Parameter(Mandatory=$False)]
			[object]$num
		)
		Switch ($kind){
			"env"  {
				Switch -regex ($num) {
					"\b(2|5|8|11)\b"    {return "COB"}
					"\b(51|52|53|54)\b" {return "DEV"}
					"\b(1|4|7|10)\b"    {return "PROD"}
					"\b(61|62|63|64)\b" {return "UAT"}
					"\b(3|6|9|12)\b"    {return "SPECIAL"}
				}
			}
			"pack" {
				Switch -regex ($num) {
					"\b(4|5|6|52|62)\b"    {return "170101_00"}
					"\b(1|2|3|51|61)\b"    {return "17080_01"}
					"\b(7|8|9|53|63)\b"    {return "180121_01"}
					"\b(10|11|12|54|64)\b" {return "18091_00"}
				}
			}
		}
	}
	Function Get-JavaBy(){
		param(
			[Parameter(Mandatory=$True)]
			[string]$version,
			[Parameter(Mandatory=$True)]
			[ValidateSet("jre", "java", "jws")]
			[string]$kind
		)
		Switch($version){
			"\b170101_00\b" {Switch($kind){ "jre" {return "jre1.7.0_101"} "java" {return "7.0.1010.14"} "jws" {return "10.101.2.14"} }}
			"\b17080_01\b"  {Switch($kind){ "jre" {return "jre1.7.0_80"}  "java" {return "7.0.800.32"}  "jws" {return "0000000"    } }}
			"\b18091_00\b"  {Switch($kind){ "jre" {return "jre1.8.0_91"}  "java" {return "8.0.910.14"}  "jws" {return "11.91.2.14" } }}
			"\b180121_01\b" {Switch($kind){ "jre" {return "jre1.8.0_121"} "java" {return "8.0.1210.13"} "jws" {return "11.121.2.13"} }}
		}
	}
	Function Get-ADMemberof(){
		param(
			[Parameter(Mandatory=$True)]
			[string]$adobject,
			[Parameter(Mandatory=$False)]
			[ValidateSet("nam", "apac", "eur")]
			[string]$domain
		)
		$Searcher = New-Object DirectoryServices.DirectorySearcher
		$Searcher.SearchRoot = "LDAP://DC=$domain,DC=nsroot,DC=net"
		$Searcher.Filter="(samaccountname=$adobject)"
		Try{
			return ($Searcher.FindOne().Properties.memberof|%{$_.split('=')[1].split(',')[0]})
		}Catch{
			return $null
		}Finally{}
	}
	$environment_PatchWave=@{
		"1"="DEV";
		"2"="UAT";
		"3"="PROD";
		"4"="PROD";
		"5"="COB"
	}
	try{$vdi,$domain,$fid,$env=$line.split(",").trim()}catch{}
	$this_path=$ActionParams[0]                            # get this running directory
	$errLog="$this_path\err.log"                           # set error log file path
	$this_user=$env:username                               # get this running script user
	$temp_csv_file="$($ActionParams[1])\$vdi-hpca.csv"     # set temp csv file to store results
	write-host "Processing in $cnt-$vdi for HPCA checking...`n"
	#<------------initilize parameters
	$waveString="$($domain)_RPA_DPT_CA_W7SP1_IE11_MSO2010_VDI_WAVE_"
	$patchString="$($domain)_RPA_DPT_PATCH_LOW_RISK_WAVE_"
	$jwsString="$($domain)_RPA_DSP_JWS_"
	$jreString="$($domain)_RPA_DSP_CA_JRE_"
	$jreString2="$($domain)_RPA_DSP_CA_ORCPJRE_"
	$hpca_results=@() ; $hpca_results+="`"Category`",`"Setting`",`"$vdi/$fid/$domain`""
	#----------------------------------------------------------#
	If( ($pcm_vdi=Get-ADMemberof "$vdi`$" $domain) -ne $null ){
		Foreach( $pv in $pcm_vdi){
			Switch -regex ($pv){
				$waveString {$wave_assignment=$_;$wave_num=$_.split('_')[-1];break}
				$patchString {$patch_assignment=$_;$patch_num=$_.split('_')[-1];break}
				$jwsString {$jws_assignment=$_;break}
			}
		}
		If( ($rst=$pcm_vdi -inotmatch "$waveString|$patchString") -ne $null ){
		   $rst|%{$hpca_results+="`"HPCA`",`"Machine Assignment $_`",`"Assigned`""}
		}
		$hpca_results+="`"HPCA`",`"Software Wave`",`"$wave_assignment`""
		$hpca_results+="`"HPCA`",`"Software Wave Environment`",`"$(Get-EnvOrPackageBy env $wave_num)`""
		$hpca_results+="`"HPCA`",`"Patching Wave`",`"$patch_assignment`""
		$hpca_results+="`"HPCA`",`"Patching Wave Environment`",`"$(Get-EnvOrPackageBy pack $patch_num)`""
	}
	#----------------------------------------------------------#
	If( ![string]::IsNullOrWhiteSpace($wave_assignment) -and (($pcm_wave=Get-ADMemberof $wave_assignment $domain) -ne $null) ){
		Foreach( $pw in $pcm_wave){
			$hpca_results+="`"HPCA`",`"Software Wave Assignment $pw`",`"Assigned`""
			If( $pw -imatch "$jreString|$jreString2" ){
				$jre_assignment=$pw
			}
		}
	}
	#----------------------------------------------------------#
	If( ![string]::IsNullOrWhiteSpace($patch_assignment) -and (($pcm_patch=Get-ADMemberof $patch_assignment $domain) -ne $null) ){
		Foreach( $pp in $pcm_patch){
			$hpca_results+="`"HPCA`",`"Patching Wave Assignment $pp`",`"Assigned`""
		}
		$javaVersion=Get-EnvOrPackageBy pack $wave_num
		If( $jre_assignment -imatch [regex]::Escape($javaVersion)){
			$hpca_results+="`"HPCA`",`"JRE Assignment`",`"JRE $javaVersion`""
		}else{
			$hpca_results+="`"HPCA`",`"JRE Assignment`",`"UNEXPECTED: ($jre_assignment) Wave $wave_num should have JRE $javaVersion`""
		}
		If( $javaVersion -eq "180121_01" ){
			$hpca_results+="`"HPCA`",`"JWS Assignment`",`"JWS $javaVersion packaged with JRE.`""
		}elseif($jws_assignment -eq "$jwsString$javaVersion"){
		   $hpca_results+="`"HPCA`",`"JWS Assignment`",`"JWS $javaVersion`""
		}else{
			$hpca_results+="`"HPCA`",`"JWS Assignment`",`"INCORRECT JWS assigned: $jws_assignment`""
		}
		If( $this_user -eq "aaadmin" ){
			$jre=Get-JavaBy $javaVersion jre
			$java_version=Get-JavaBy $javaVersion java
			$jws_version=Get-JavaBy $javaVersion jws
			$java_exe_path="\\$vdi\c$\Program Files (x86)\JAVA\$jre\bin\java.exe"
			$jws_exe_path="\\$vdi\c$\Program Files (x86)\JAVA\$jre\bin\javaws.exe"
			If( (get-item $java_exe_path -ErrorAction Ignore).VersionInfo.fileversion -eq $java_version){
				$hpca_results+="`"HPCA`",`"Java Installed`",`"Expected Version`""
			}else{
				$hpca_results+="`"HPCA`",`"Java Installed`",`"Expected Version`""
			}
			If( (get-item $jws_exe_path -ErrorAction Ignore).VersionInfo.fileversion -eq $jws_version){
				$hpca_results+="`"HPCA`",`"JWS Installed`",`"Expected Version`""
			}else{
				$hpca_results+="`"HPCA`",`"JWS Installed`",`"Expected Version`""
			}
		}else{
			$hpca_results+="`"HPCA`",`"Java Installed`",`"To check installs on machine, run as aaadmin`""
			$hpca_results+="`"HPCA`",`"JWS Installed`",`"To check installs on machine, run as aaamin`""
		}
	}
	$hpca_results -replace('Assigned','1')|out-file -FilePath $temp_csv_file -Encoding utf8 -Force
	$temp=import-csv $temp_csv_file|sort Setting
	$temp|Export-Csv -Path $temp_csv_file -UseCulture -NoTypeInformation -Encoding UTF8 -Force -ErrorAction Ignore
	Write-Host -ForegroundColor Yellow "--Done getting $cnt-$vdi hpca info--`n"
}
Start-BulkThreads $inputlist $hpca_action $this_path,$hpca_temp_path -maxCnt 100
#<--------------------------------------------------- combine single csv file to be one total csv file( and exclude equal values for 2 csv files)
$total_hpca_csv_files=(dir $hpca_temp_path\*.csv).FullName|sort
If( $total_hpca_csv_files.count -gt 2 ){ #<------------------- return total data if there are more than 2 csv files
	$temp_csv_path="$this_path\temp_csv" ; 	New-FileOrFolder $temp_csv_path -d
	copy "$hpca_temp_path\*.csv" "$temp_csv_path\" -recurse -force
	$combine_csv_action={
		param($line,$cnt,$ActionParams)
		Function Combine-Csv(){
			param(
			[Parameter(Mandatory=$True)]
			[string[]]$csv_pair,            # the 2 csv files to be managed
			[Parameter(Mandatory=$false)]   
			[string]$key="IE"               # the Category of csv file
		)
			$csv_file1,$csv_file2=$csv_pair
			$total_csv_info=[ordered]@{}
			#<------------------------------ 1st csv ----------------------------------------
			$csv_text_content1=(Get-Content $csv_file1 -ReadCount 0) -replace('\x00','') # remove nul in the text file
			$csv_csv_content1=ipcsv $csv_file1
			$csv_header_count1=($csv_csv_content1|gm -MemberType NoteProperty).count
			[string[]]$csv_settings1+='"setting"'
			$csv_csv_content1.setting|%{$csv_settings1+="`"$_`""} # get all 1st csv registries
			#<------------------------------ 2nd csv ---------------------------------------- 
			$csv_text_content2=(Get-Content $csv_file2 -ReadCount 0) -replace('\x00','') # remove nul in the text file
			$csv_csv_content2=ipcsv $csv_file2
			$csv_header_count2=($csv_csv_content2|gm -MemberType NoteProperty).count
			[string[]]$csv_settings2+='"setting"'
			$csv_csv_content2.setting|%{$csv_settings2+="`"$_`""} # get all 2nd csv registries
			#<----------- add each line from 1st csv to the total ie hash table -------------------
			For( $i=0; $i -lt $csv_settings1.count; $i++ ){
				$total_csv_info.Add($csv_settings1[$i],$csv_text_content1[$i])
			}
			#<--- add (,"N/A") at end of the line if 1sr csv settings not in 2nd csv file settings ---
			Foreach( $line in (compare $csv_settings1 $csv_settings2|?{$_.SideIndicator -eq "<="}).InputObject){
				$total_csv_info.$line+=',"N/A"' * ($csv_header_count2 - 2) 
			}
			#<----------------- loop each setting of 2nd csv file -----------------
			For( $i=0; $i -lt $csv_settings2.count; $i++ ){
				$this_setting=$csv_settings2[$i] # get registry key and value
				$this_line = $csv_text_content2[$i] -split(',"')
				$this_setting_value=[string]::Join(',',($this_line[(2 .. ($this_line.count-1))]|%{'"' + $_}))
				If($this_setting -in $csv_settings1 ){ # if the setting in 2nd csv is in 1st csv settings
					$total_csv_info.$this_setting+=",$this_setting_value" 
				}else{$total_csv_info.Add($this_setting,"`"$key`",$this_setting,"+'"N/A",' * ($csv_header_count1 - 2) +$this_setting_value) }
			}
			[string[]]$total_csv_info.Values|out-file -FilePath $csv_file1 -Encoding utf8 -Force
			del $csv_file2 -Force ; return $csv_file1
		}
		$csv1,$csv2=$ActionParams[($cnt * 2-2),($cnt * 2 -1)]
		write-host "Combinding $cnt : $($cnt * 2 -1)-$($cnt * 2) csv files |$csv1|<-->|$csv2|`n"
		return (Combine-Csv $csv1,$csv2 HPCA)
	}
	$total_hpca_csv_files=(dir $temp_csv_path\*.csv).FullName|sort
	Do{
		$total_hpca_csv_cnt=$total_hpca_csv_files.count
		If( ($total_hpca_csv_cnt % 2) -eq 1 ){
			$last_csv=$total_hpca_csv_files[-1]
		}else{$last_csv=$null}
		[string[]]$total_hpca_csv_files=Start-BulkThreads @(1.. [math]::Truncate($total_hpca_csv_cnt/2)) $combine_csv_action $total_hpca_csv_files -maxCnt 50|sort
		If( $last_csv ){
			$total_hpca_csv_files+=$last_csv
		}
		Write-Host -ForegroundColor Yellow "Done combinding $total_hpca_csv_cnt csv files"
	}While( $total_hpca_csv_files.count -gt 1)
	move-item $total_hpca_csv_files "$this_path\hpca.csv" -force; del $temp_csv_path -recurse -force
	Write-Host -ForegroundColor Yellow "Done export 'hpca settings' to '$this_path\hpca.csv' in $(([math]::Round(((get-date)-$st).totalseconds))) s."
}elseif($total_hpca_csv_files.count -eq 2){ #<---------------------------- exclude equal values if there are 2 csv files
	$csv_hashtable1=[ordered]@{};$csv_hashtable2=[ordered]@{} ; $csv_settings1=@();$csv_settings2=@()
	$csv1,$csv2=$total_hpca_csv_files|%{Get-Content $_ -ReadCount 0}
	$rst=compare $csv1 $csv2
	$rst|?{$_.SideIndicator -eq "<="}|%{ # load 1st csv settings and values
		$line=$_.InputObject ; $setting=($line -split('","'))[1]
		$csv_settings1+=$setting
		$csv_hashtable1.Add($setting,$line)
	}
	$rst|?{$_.SideIndicator -eq "=>"}|%{ # load 2nd csv settings and values
		$line=$_.InputObject ; $setting=($line -split('","'))[1]
		$csv_settings2+=$setting
		$csv_hashtable2.Add($setting,$line)
	}
	$total_hpca_info=@()
	Foreach( $setting in $csv_settings1){ # manager 1st csv file data
		If( $setting -inotin $csv_settings2){
			$value=',"0"'
		}else{
			$value=','+($csv_hashtable2.$setting -split('",'))[2]
		}
		$total_hpca_info+=$csv_hashtable1.$setting+$value
	}
	$csv_settings2|?{$_ -inotin $csv_settings1}|%{ # manager 2nd csv file data
		$value=$csv_hashtable2.$_
		$sec_num=$value.LastIndexOf('",')
		$total_hpca_info+=$value.Substring(0,$sec_num+3)+"0$($value.Substring($sec_num))"
	}
	Export-Result $total_hpca_info '"hpca settings"' "$this_path\hpca.csv" ([math]::Round(((get-date)-$st).totalseconds)) -outfile
}
